import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, MoreThan, DataSource } from "typeorm";
import { CharacterInventoryEntity } from "../entities/character-inventory.entity";
import { CharacterMineralEntity } from "../entities/character-mineral.entity";
import { CharacterStoneEntity } from "../entities/character-stone.entity";
import { CharacterResourcesEntity } from "../entities/character-resources.entity";
import { BasicItemEntity } from "../entities/basic-item.entity";
import { CharacterEquipmentInventoryEntity } from "../entities/character-equipment-inventory.entity";
import { EquipmentGemSocketEntity } from "../entities/equipment-gem-socket.entity";
import { GemBaseEntity } from "../entities/gem-base.entity";
import { GemAttributeEntity } from "../entities/gem-attribute.entity";

@Injectable()
export class InventoryService {
  constructor(
    @InjectRepository(CharacterInventoryEntity)
    private inventoryRepository: Repository<CharacterInventoryEntity>,
    @InjectRepository(CharacterMineralEntity)
    private mineralRepository: Repository<CharacterMineralEntity>,
    @InjectRepository(CharacterStoneEntity)
    private stoneRepository: Repository<CharacterStoneEntity>,
    @InjectRepository(CharacterResourcesEntity)
    private resourcesRepository: Repository<CharacterResourcesEntity>,
    @InjectRepository(BasicItemEntity)
    private basicItemRepository: Repository<BasicItemEntity>,
    @InjectRepository(CharacterEquipmentInventoryEntity)
    private equipmentInventoryRepository: Repository<CharacterEquipmentInventoryEntity>,
    @InjectRepository(EquipmentGemSocketEntity)
    private equipmentGemSocketRepository: Repository<EquipmentGemSocketEntity>,
    @InjectRepository(GemBaseEntity)
    private gemBaseRepository: Repository<GemBaseEntity>,
    @InjectRepository(GemAttributeEntity)
    private gemAttributeRepository: Repository<GemAttributeEntity>,
    private readonly dataSource: DataSource
  ) {}

  /**
   * 根据属性类型获取属性名称
   */
  async getAttributeName(attributeType: number): Promise<string> {
    try {
      // 从gem_attributes表查询属性名称
      const results = await this.gemAttributeRepository.query(
        `SELECT attribute_name FROM gem_attributes WHERE id = ?`,
        [attributeType]
      );

      if (results.length > 0) {
        return results[0].attribute_name;
      }

      return "未知属性";
    } catch (error) {
      console.error("获取属性名称失败:", error);
      return "未知属性";
    }
  }

  /**
   * 查询矿石+矿盒背包列表（按物品汇总）
   */
  async getMineralList(
    characterId: number,
    pageNum: number = 0
  ): Promise<
    Array<{
      id: number;
      lvl: number;
      name: string;
      num: number;
      pic: string;
      type: number;
    }>
  > {
    // 新版：从独立矿石背包表 character_mineral 聚合
    const take = 200;
    const skip = pageNum * take;
    const qb = this.mineralRepository
      .createQueryBuilder("m")
      .innerJoin(BasicItemEntity, "bi", "bi.id = m.itemId")
      .where("m.characterId = :cid AND m.status = 1 AND m.num > 0", {
        cid: characterId,
      })
      .andWhere("(bi.name LIKE :k1 OR bi.name LIKE :k2)", {
        k1: "%矿%",
        k2: "%宝盒%",
      })
      .select([
        "m.itemId as id",
        "SUM(m.num) as num",
        "MAX(bi.name) as name",
        "MAX(bi.lv) as lvl",
        "MAX(bi.pic) as pic",
      ])
      .groupBy("m.itemId")
      .orderBy("id", "ASC")
      .limit(take)
      .offset(skip);
    const rows = await qb.getRawMany<{
      id: number;
      num: string;
      name: string;
      lvl: number;
      pic: string;
    }>();
    return rows.map((r) => ({
      id: Number(r.id),
      lvl: Number(r.lvl || 0),
      name: r.name || "",
      num: Number(r.num || 0),
      pic: r.pic || "none.png",
      type: 5,
    }));
  }

  /**
   * 向矿石背包添加（合并叠加）
   */
  async addMineral(
    characterId: number,
    itemId: number,
    count: number
  ): Promise<void> {
    const exist = await this.mineralRepository.findOne({
      where: { characterId, itemId, status: 1 },
    });
    if (exist) {
      await this.mineralRepository.update(
        { id: exist.id },
        { num: exist.num + count, updated_at: new Date() }
      );
    } else {
      await this.mineralRepository.insert({
        characterId,
        itemId,
        num: count,
        status: 1,
        created_at: new Date(),
        updated_at: new Date(),
      });
    }
  }

  /**
   * 从矿石背包丢弃（按数量），返回剩余
   */
  async discardMineral(
    characterId: number,
    itemId: number,
    count: number
  ): Promise<number> {
    const row = await this.mineralRepository.findOne({
      where: { characterId, itemId, status: 1 },
    });
    if (!row || row.num < count) throw new Error("背包中矿石数量不足");
    const left = row.num - count;
    if (left > 0) {
      await this.mineralRepository.update(
        { id: row.id },
        { num: left, updated_at: new Date() }
      );
    } else {
      await this.mineralRepository.update(
        { id: row.id },
        { status: -1, num: 0, updated_at: new Date() }
      );
    }
    return Math.max(0, left);
  }

  /**
   * 丢弃（自动判断矿石/矿盒走矿石表，否则走杂物表）
   */
  async discardItemAuto(
    characterId: number,
    itemId: number,
    count: number
  ): Promise<{ success: boolean; message: string; remainingCount?: number }> {
    // 优先看矿石表是否存在
    const mineral = await this.mineralRepository.findOne({
      where: { characterId, itemId, status: 1 },
    });
    if (mineral) {
      const left = await this.discardMineral(characterId, itemId, count);
      return {
        success: true,
        message: `您丢弃了一个${
          (await this.basicItemRepository.findOne({ where: { id: itemId } }))
            ?.name || "物品"
        }`,
        remainingCount: left,
      };
    }
    // 否则走杂物表
    return this.discardItemFromInventory(characterId, itemId, count);
  }

  /**
   * 查询角色背包药品信息 (1416)
   * 注意：此方法应该调用CharacterMedicineService，而不是直接查询inventory表
   * 药品应该存储在character_medicine表中，而不是character_inventory表中
   */
  async getCharacterMedicine(
    characterId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ) {
    // 这个方法应该被废弃，药品查询应该直接使用CharacterMedicineService
    throw new Error(
      "药品查询应该使用CharacterMedicineService.getCharacterMedicine方法"
    );
  }

  /**
   * 查询角色背包装备信息 (1423)
   */
  async getCharacterStatus(
    characterId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ) {
    try {
      console.log(
        `🔍 查询角色${characterId}的装备背包，页码${pageNum}，页大小${pageSize}`
      );

      const [items, total] =
        await this.equipmentInventoryRepository.findAndCount({
          where: {
            characterId,
            status: 1,
          },
          skip: pageNum * pageSize,
          take: pageSize,
          // 先按装备等级升序，再按获得时间降序，确保分页前排序
          order: { level: "ASC", obtainedAt: "DESC" },
          relations: ["equipmentBase"], // 关联装备基础表
        });

      console.log(`📦 找到${total}个装备，当前页${items.length}个`);

      // 获取属性名称映射（直接从gem_attributes表获取）
      const attributeNameMap = new Map<number, string>();
      const gemAttributes = await this.gemAttributeRepository.query(
        "SELECT id, short_name FROM gem_attributes"
      );
      gemAttributes.forEach((attr: any) => {
        // 使用gem_attributes表的id作为属性类型，short_name作为属性简称
        attributeNameMap.set(attr.id, attr.short_name);
      });

      // 为每个装备查询宝石槽信息
      const list = await Promise.all(
        items.map(async (item: any) => {
          // 查询该装备的宝石槽信息
          const gemSockets = await this.equipmentGemSocketRepository.find({
            where: {
              characterId,
              equipmentId: item.id, // 使用装备背包记录的ID，而不是equipmentId
            },
            order: { socketSlot: "ASC" },
          });

          // 构建宝石槽字符串
          const stoneSlots = ["空", "空", "空"];
          gemSockets.forEach((socket) => {
            if (socket.socketSlot >= 1 && socket.socketSlot <= 3) {
              const attributeName =
                attributeNameMap.get(socket.gemAttributeType) || "未知属性";
              // 注意：1423指令使用简化的属性名称（如"雷"、"沙"），这是特意设计的
              // 与1062指令的完整属性名称（如"抗落雷"、"抗风沙"）不同，用于区分列表和详情显示
              stoneSlots[
                socket.socketSlot - 1
              ] = `${attributeName}+${socket.gemAttributeValue}点`;
            }
          });

          return {
            id: item.id,
            level: item.level,
            lock: false, // 默认未锁定
            name: item.name || item.equipmentBase?.name || "",
            stone: `(${stoneSlots.join(",")})`,
          };
        })
      );

      return {
        list,
        total,
        page: pageNum + 1,
        sum: total,
      };
    } catch (error) {
      console.error("查询角色背包装备失败:", error);
      throw error;
    }
  }

  /**
   * 查询角色背包石头 (6034)
   */
  async getCharacterStones(
    characterId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ) {
    try {
      const [stones, total] = await this.stoneRepository.findAndCount({
        where: {
          characterId,
        },
        skip: pageNum * pageSize,
        take: pageSize,
        order: { created_at: "DESC" },
      });

      // 按照标准指令说明文档的格式返回数据
      const list = stones.map((stone: any) => ({
        id: stone.id,
        lvl: stone.level,
        name: stone.name,
        num: 1, // 石头数量默认为1
        type: stone.type || 1,
      }));

      return {
        list,
        total,
        page: pageNum + 1,
        sum: total,
      };
    } catch (error) {
      console.error("查询角色背包石头失败:", error);
      throw error;
    }
  }

  /**
   * 查询角色背包杂物 (1425)
   */
  async getCharacterMisc(
    characterId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ) {
    try {
      const [items, total] = await this.inventoryRepository.findAndCount({
        where: {
          characterId,
          status: 1,
          num: MoreThan(0), // 只查询数量大于0的物品
        },
        skip: pageNum * pageSize,
        take: pageSize,
        order: { obtainedAt: "DESC" },
        relations: ["basicItem"],
      });

      // 按照标准指令说明文档的格式返回数据
      const data = items.map((item: any) => ({
        id: item.itemId, // 使用物品ID而不是背包ID
        name: item.name || item.basicItem?.name || "",
        num: item.num,
        pic: item.pic || item.basicItem?.pic || "",
      }));

      return {
        data,
        total,
        page: pageNum + 1,
        sum: total,
      };
    } catch (error) {
      console.error("查询角色背包杂物失败:", error);
      throw error;
    }
  }

  /**
   * 更新背包物品数量
   */
  async updateItemQuantity(inventoryId: number, quantity: number) {
    try {
      const result = await this.inventoryRepository.update(inventoryId, {
        num: quantity,
        updated_at: new Date(),
      });
      return (result.affected || 0) > 0;
    } catch (error) {
      console.error("更新背包物品数量失败:", error);
      throw error;
    }
  }

  /**
   * 删除背包物品
   */
  async removeItemFromInventory(inventoryId: number) {
    try {
      const result = await this.inventoryRepository.update(inventoryId, {
        status: -1, // 标记为已丢弃
        updated_at: new Date(),
      });
      return (result.affected || 0) > 0;
    } catch (error) {
      console.error("删除背包物品失败:", error);
      throw error;
    }
  }

  /**
   * 添加物品到背包杂物表
   */
  async addItemToInventory(
    characterId: number,
    itemId: number,
    count: number
  ): Promise<{ success: boolean; message: string }> {
    try {
      // 获取物品信息
      const item = await this.basicItemRepository.findOne({
        where: { id: itemId, status: 1 },
      });

      if (!item) {
        throw new Error("物品不存在");
      }

      // 检查背包中是否已存在此物品
      const existingItem = await this.inventoryRepository.findOne({
        where: { characterId, itemId: item.id, status: 1 },
      });

      if (existingItem) {
        // 如果已存在，进行数量叠加
        await this.inventoryRepository.update(
          { id: existingItem.id },
          {
            num: existingItem.num + count,
            updated_at: new Date(),
          }
        );
      } else {
        // 如果不存在，创建新记录
        await this.inventoryRepository.insert({
          characterId,
          itemId: item.id,
          name: item.name,
          itemType: item.lv, // 使用物品等级作为物品类型
          num: count,
          status: 1,
          pic: item.pic,
          description: item.description,
          level: item.lv,
          rarity: 1, // 默认稀有度
          obtainedAt: new Date(),
          created_at: new Date(),
          updated_at: new Date(),
        });
      }

      return {
        success: true,
        message: `成功添加 ${count} 个${item.name}到背包`,
      };
    } catch (error) {
      console.error("添加物品到背包失败:", error);
      throw error;
    }
  }

  /**
   * 丢弃背包物品（按数量）
   */
  async discardItemFromInventory(
    characterId: number,
    itemId: number,
    count: number = 1
  ): Promise<{ success: boolean; message: string; remainingCount?: number }> {
    try {
      // 查找背包中的物品
      const inventoryItem = await this.inventoryRepository.findOne({
        where: {
          characterId,
          itemId,
          status: 1, // 只查找正常状态的物品
        },
      });

      if (!inventoryItem) {
        return {
          success: false,
          message: "背包中没有该物品",
        };
      }

      if (inventoryItem.num < count) {
        return {
          success: false,
          message: `背包中该物品数量不足，当前数量：${inventoryItem.num}`,
        };
      }

      const remainingCount = inventoryItem.num - count;

      if (remainingCount <= 0) {
        // 如果丢弃后数量为0或负数，直接删除该物品记录
        await this.inventoryRepository.update(inventoryItem.id, {
          status: -1, // 标记为已丢弃
          updated_at: new Date(),
        });
        return {
          success: true,
          message: `成功丢弃 ${count} 个${inventoryItem.name}`,
          remainingCount: 0,
        };
      } else {
        // 如果还有剩余，更新数量
        await this.inventoryRepository.update(inventoryItem.id, {
          num: remainingCount,
          updated_at: new Date(),
        });
        return {
          success: true,
          message: `成功丢弃 ${count} 个${inventoryItem.name}，剩余 ${remainingCount} 个`,
          remainingCount,
        };
      }
    } catch (error) {
      console.error("丢弃背包物品失败:", error);
      throw error;
    }
  }

  /**
   * 获取角色背包总览
   */
  async getInventoryOverview(characterId: number) {
    try {
      const [totalItems, totalStones, resources] = await Promise.all([
        this.inventoryRepository.count({
          where: {
            characterId,
            status: 1,
          },
        }),
        this.stoneRepository.count({
          where: {
            characterId,
          },
        }),
        this.resourcesRepository.findOne({
          where: { characterId },
        }),
      ]);

      return {
        totalItems,
        totalStones,
        resources: resources
          ? {
              gold: resources.gold,
              silver: resources.silver,
              bdSilver: resources.bdSilver,
              fc: resources.fc,
              superHK: resources.superHK,
              tlz: resources.tlz,
              tlzs: resources.tlzs,
              vipBag: resources.vipBag,
            }
          : null,
      };
    } catch (error) {
      console.error("获取背包总览失败:", error);
      throw error;
    }
  }

  /**
   * 根据角色ID和物品ID获取背包中的物品
   */
  async getCharacterInventoryItem(characterId: number, itemId: number) {
    try {
      const item = await this.inventoryRepository.findOne({
        where: {
          characterId,
          itemId,
          status: 1, // 只获取正常状态的物品
        },
      });
      return item;
    } catch (error) {
      console.error("获取背包物品失败:", error);
      throw error;
    }
  }

  /**
   * 查询角色背包中将军令的数量
   * @param characterId 角色ID
   * @returns 将军令数量统计
   */
  async getGeneralTokenCounts(characterId: number) {
    try {
      // 查询所有将军令相关的物品
      const items = await this.inventoryRepository.find({
        where: {
          characterId,
          status: 1, // 只获取正常状态的物品
        },
        relations: ["basicItem"],
      });

      // 统计各种将军令的数量
      let djjl = 0; // 大将军令 (ID: 69)
      let djjl_bd = 0; // 大将军令(绑) (ID: 331)
      let jjl = 0; // 将军令 (ID: 68)
      let jjl_bd = 0; // 将军令(绑) (ID: 141)

      items.forEach((item) => {
        switch (item.itemId) {
          case 69: // 大将军令
            djjl += item.num;
            break;
          case 331: // 大将军令(绑)
            djjl_bd += item.num;
            break;
          case 68: // 将军令
            jjl += item.num;
            break;
          case 141: // 将军令(绑)
            jjl_bd += item.num;
            break;
        }
      });

      return {
        djjl,
        djjl_bd,
        jjl,
        jjl_bd,
      };
    } catch (error) {
      console.error("查询将军令数量失败:", error);
      throw error;
    }
  }
}
